﻿using FlyIL.Trace;
using System.Collections.Generic;

namespace FlyIL.Optimizer
{

    /* 
     * 平衡栈 , 删除 无意义的 栈 赋值 , 以及 栈内读写  
     * 
     */
    public static class 栈变量化简扩展
    {




        #region fix 

        /// <summary>
        /// nop 掉多弹栈语句，并且将对应的入栈(可以是多条)， nop掉，以保持栈平衡
        /// *** 副作用 会把上面的 pop 语句也一并nop 掉 ， 
        /// 不以化简到0 为目标， 到化多少 就化多少 
        /// 同时对其间的 栈访问进行修正
        /// </summary>
        /// <returns> 返回的初始的push 节点 </returns>
        internal static Inst Nop_Multi_Pops(this Context vcontext, Inst node, int? offset)
        {
            var inst = node;

            if (offset == null || offset <= 0)
                return null;


            /// 能退多少算多少 


            int fix = (int)offset;
            var it = vcontext.GetPreviousIfExist(node);
            for (; it != null; it = vcontext.GetPreviousIfExist(it))
            {
                var c = it;
                var nnn = c.SpVariety;
                if (nnn == null)
                    continue;


                if ((fix + nnn) < 0 && c.Opt != Opt.lea)
                    break;


                if (nnn == 0)
                {
                    /// 需要对 op1 进行追踪 
                    if (c.O2.IsStackValue)
                    {
                        if ((c.O2.u32 + c.O2.ByteSize) <= fix)
                        {
                            Operand op = c.O2;
                            var exp = vcontext.TraceStrict(vcontext.GetPreviousIfExist(it), ref op);
                            if (exp == null)
                                return null;
                            if (exp.Calculable)
                                c.O2 = Operand.Make(exp.Result, c.O2.ByteSize);
                            else
                                c.O2 = exp.FinalLeft<Operand>();


                        }
                        else
                            c.O2.u32 -= (uint)fix;
                    }
                    if (!c.IsAlter)
                        continue;

                    if (c.O1.IsStackValue)
                    {
                        if ((c.O1.u32 + c.O1.ByteSize) <= fix)
                            it.nop();
                        else
                            c.O1.u32 -= (uint)fix;
                    }
                }

                /// 弹栈语句   压栈语句 
                else
                {

                    if (c.Opt == Opt.pop)
                    {
                        var nod = vcontext.TraceStrict(it, ref c.O1);
                        if (nod == null)
                            it.nop();
                        else if (nod.CalcDepth == 0)
                            it.mov(c.O1, nod.FinalLeft<Operand>());
                        else
                            it.nop();
                    }
                    else
                    {
                        it.nop();
                    }

                    fix += (int)nnn;


                }

            }


            if (fix == 0)
            {
                node.nop();
                return it;
            }
            else
            {
                var reg = vcontext.RegSpExp;
                node.lea(reg, reg + fix);
            }
            return null;

        }




        /// <summary>
        /// nop 掉 单一条弹栈语句，并且将对应的入栈 nop掉，以保持栈平衡 
        /// 同时对其间的 栈访问进行修正
        /// </summary>
        /// <returns> 返回的对应的push 节点 </returns>
        internal static Inst Nop_And_Fix_A_StackAccess(this Context vcontext, Inst node, int start, int? width)
        {
            var inst = node;

            if (width == null || width == 0 || width < 0)
                return null;

            node.nop();

            int sk = start;
            for (var it = vcontext.GetPreviousIfExist(node); it != null; it = vcontext.GetPreviousIfExist(it))
            {
                var nnn = it.SpVariety;
                if (nnn == null)
                    continue;

                var c = it;
                /// 该指令不影响栈项
                if (nnn == 0)
                {
                    if (c.O2.IsStackValue)
                    {
                        if ((c.O2.u32 + c.O2.ByteSize) <= width)
                        {
                            Operand op = c.O2;
                            var exp = vcontext.TraceStrict(vcontext.GetPreviousIfExist(it), ref op);
                            if (exp == null)
                                throw new System.Exception();
                            if (exp.Calculable)
                                c.O2 = Operand.Make(exp.Result, c.O2.ByteSize);
                            else if (exp.CalcDepth == 0)
                                c.O2 = exp.FinalLeft<Operand>();

                        }
                        else
                            c.O2.u32 -= (uint)width;
                    }
                    if (!c.IsAlter)
                        continue;

                    if (c.O1.IsStackValue)
                    {
                        if ((c.O1.u32 + c.O1.ByteSize) <= sk)
                        {
                            ;
                        }
                        else if (sk < c.O1.u32)
                            c.O1.u32 -= (uint)width;
                        else
                            it.nop();
                    }
                }
                /// 有入栈和出栈 
                else
                {
                    if (sk > 0)
                        sk += (int)nnn;
                    else if (sk < 0)
                        return null;
                    else
                    {
                        if ((-nnn) <= width)
                        {
                            /// 如果 对于 call , 要将其 入栈去掉 ,则转换为 jmp 语句
                            /// 此处是  在后部添加  
                            if (it.Opt == Opt.call)
                            {
                                vcontext.InsertAfter(it).jmp(it.O1);
                            }
                            it.nop();


                            width += nnn;

                            if (width == 0)
                                return it;
                        }
                        else
                            throw new System.Exception("不合理的退栈 ");
                    }
                }

            }

            return null;

        }




        #endregion



    }
}
